package com.yanqu.road.server.manger.activity.washe;

import com.yanqu.road.entity.DataStatus;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.washe.config.WasheConfig;
import com.yanqu.road.entity.activity.washe.config.WasheSeasonConfig;
import com.yanqu.road.entity.activity.washe.config.WasheSkillConfig;
import com.yanqu.road.entity.activity.washe.data.*;
import com.yanqu.road.entity.config.badge.BadgeConfig;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.enums.washe.eWasheFunction;
import com.yanqu.road.entity.enums.washe.eWasheHonorMomentType;
import com.yanqu.road.entity.enums.washe.eWasheSkillType;
import com.yanqu.road.entity.log.LogWasheDisconnect;
import com.yanqu.road.entity.player.UserBadge;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.entity.rank.xrank.XSeasonUserRank;
import com.yanqu.road.entity.season.SeasonRewardConfig;
import com.yanqu.road.entity.season.SeasonRewardData;
import com.yanqu.road.logic.bussiness.activity.SeasonRewardBusiness;
import com.yanqu.road.logic.bussiness.activity.WasheBusiness;
import com.yanqu.road.logic.bussiness.player.UserBadgeBussiness;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.helper.SeasonHelper;
import com.yanqu.road.logic.pb.WashePb2;
import com.yanqu.road.pb.activity.WasheProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.washe.WasheModule;
import com.yanqu.road.server.gameplayer.module.player.BadgeModule;
import com.yanqu.road.server.gameplayer.module.season.SeasonRewardModule;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.manger.MultipleLanguageMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.config.BadgeConfigMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.season.SeasonRewardMgr;
import com.yanqu.road.server.manger.system.SystemSwitchMgr;
import com.yanqu.road.server.protocol.ChannelProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class WasheMgr extends TempMgr {

    private final static Object reloadConfigLock = new Object();
    public static WasheConfig washeConfig;

    // 游戏时的ping
    public static final Map<Long, WasheUserPingData> pingMap = new ConcurrentHashMap<>();

    // 勋章数据（其他玩家可以查看）
    public static long badgeClearTime = System.currentTimeMillis();
    public static final Map<Long, WasheTmpBadgeResult> badgeResultMap = new ConcurrentHashMap<>();

    // 最后一次对局结果
    public static final Map<Long, WasheLastResultData> lastResultMap = new ConcurrentHashMap<>();

    // 赛季排名     赛季id，榜单类型，rank
    public static Map<Integer, Map<Integer, WasheHistoryRank>> historyRankMap = new ConcurrentHashMap<>();

    // 战令自动发奖（缓存不入库）
    private static final Set<Integer> autoZhanLingSeasonSet = new HashSet<>();

    // 今日玩法（跨域同步下来）
    private static List<Integer> sceneList = new ArrayList<>();
    private static long syncSceneTime = 0;

    public static void reloadActivityData() {

        synchronized (reloadConfigLock) {

            getLogger().info("reload washe begin");

            // 先检查有没有数据库连接配置
            String dbParam = ChannelConfig.CHANNEL_CENTER_DB_PARAM;
            if ("0".equals(dbParam)) {
                washeConfig = null;
                getLogger().info("[ ChannelConfig.CHANNEL_CENTER_DB_PARAM ] is zero!");
                return;
            }

            // 拿活动（活动时间内，且channelId对得上）
            List<ActivityInfo> list = NormalActivityMgr.getOpenActivityInfoList(eActivityType.WasheActivity.getValue());
            if (list.isEmpty()) {
                washeConfig = null;
                SeasonRewardMgr.clearSeasonRewardConfigMap(eSystemId.WasheActivity.getValue());
                getLogger().info("reload washe finish, no activity in show time.");
                return;
            }
            ActivityInfo activityInfo = list.get(0);
            int activityId = activityInfo.getActivityId();

            Map<String, ActivityConfig> activityConfigMap = NormalActivityMgr.getActivityConfigMap(activityId);

            // 【生成配置】不要换顺序
            WasheConfig config = new WasheConfig();
            config.setActivityInfo(activityInfo);
            config.initActivityConfig(activityConfigMap, ChannelConfig.CHANNEL_ACTIVITY_TIME_ZONE);
            config.setNewHandScore(WasheBusiness.getWasheNewHandScore(dbParam, activityId));
            config.setSeasonConfigMap(WasheBusiness.getWasheSeasonTimeConfigMap(dbParam, activityId, ChannelConfig.CHANNEL_ACTIVITY_TIME_ZONE));
            config.setRankConfigMap(WasheBusiness.getWasheRankConfigMap(dbParam, activityId, config.getLastSeasonId())); // 放在setSeasonConfigMap后面
            config.setBoxConfigListMap(WasheBusiness.getWasheBoxConfigListMap(dbParam, activityId, config.getLastSeasonId(), config.getVersion())); // 放在setSeasonConfigMap后面
            config.setModeConfigMap(WasheBusiness.getWasheModeConfigMap(dbParam, activityId));
            config.setSceneConfigMap(WasheBusiness.getWasheSceneConfigMap(dbParam, activityId));
            config.setCardConfigMap(WasheBusiness.getWasheCardConfigMap(dbParam, activityId));
            config.setSkillConfigMap(WasheBusiness.getWasheSkillConfigMap(dbParam, activityId));
            config.setHonorMomentConfigMap(WasheBusiness.getWasheHonorMomentConfigMap(dbParam, activityId));
            config.setRoundConfigMap(WasheBusiness.getWasheRoundConfigMap(dbParam, activityId, config.getLastSeasonId(), ChannelConfig.CHANNEL_ACTIVITY_TIME_ZONE));

            // 替换配置
            washeConfig = config;

            // 赛季奖励配置
            WasheSeasonConfig curWasheSeasonConfig = washeConfig.getWasheSeasonConfig();
            if (curWasheSeasonConfig != null) {
                SeasonRewardMgr.reloadSeasonRewardConfigMap(eSystemId.WasheActivity.getValue(), washeConfig.getActivityInfo().getActivityId(), curWasheSeasonConfig.getSeasonId());
            } else {
                SeasonRewardMgr.reloadSeasonRewardConfigMap(eSystemId.WasheActivity.getValue(), washeConfig.getActivityInfo().getActivityId(), WasheConfig.SEASON_ID_NULL);
            }

            // 在线玩家刷新
            for (GamePlayer player : GamePlayerMgr.getAllOnlinePlayer()) {
                player.getModule(WasheModule.class).refreshData();
            }

            getLogger().info("reload washe finish, activityId {}.", activityInfo.getActivityId());

        }
    }

    // =========================================

    public static WasheConfig getWasheConfig() {
        return washeConfig;
    }

    public static WasheUserKey getUserKey(long userId) {
        long serverId = GameServer.getInstance().getServerId();
        int channelId = ServerListMgr.getChannelId(serverId);

        WasheUserKey userKey = new WasheUserKey();
        userKey.setUserId(userId);
        userKey.setServerId(serverId);
        userKey.setChannelId(channelId);
        return userKey;
    }

    public static boolean ping(long userId) {
        synchronized (pingMap) {
            WasheUserPingData data = pingMap.get(userId);
            if (data == null) {
                return false;
            }

            // 掉线被检测后2秒内重连，每次都上传重连，避免跟掉线顺序乱掉
            if (data.isDisconnect()) {
                long disconnectTime = (long) (washeConfig.getPingInterval() * washeConfig.getDisconnectPingTimes());
                long costTime = System.currentTimeMillis() - data.getPingTime();
                if (costTime - disconnectTime < 2000) {
                    // 上传掉线恢复
                    WasheProto.ChannelWasheStatusReqMsg.Builder builder = WasheProto.ChannelWasheStatusReqMsg.newBuilder();
                    builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(getUserKey(userId)));
                    builder.setType(2);
                    GamePlayerMgr.sendChannelPacket(ChannelProtocol.N_WASHE_STATUS, builder, userId);
                    return true;
                }
            }

            // 掉线重连加个日志
            if (data.isDisconnect()) {
                // 日志
                AutoLogMgr.add(new LogWasheDisconnect(userId, 2, new Date(data.getPingTime())));
            }

            data.setPingTime(System.currentTimeMillis());

            if (data.isDisconnect()) {
                // 断线重连
                data.setDisconnect(false);

                // 上传掉线恢复
                WasheProto.ChannelWasheStatusReqMsg.Builder builder = WasheProto.ChannelWasheStatusReqMsg.newBuilder();
                builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(getUserKey(userId)));
                builder.setType(2);
                GamePlayerMgr.sendChannelPacket(ChannelProtocol.N_WASHE_STATUS, builder, userId);
            }
            return true;
        }
    }

    public static void removePing(long userId) {
        synchronized (pingMap) {
            pingMap.remove(userId);
        }
    }

    public static void beginPing(long userId) {
        synchronized (pingMap) {
            WasheUserPingData data = pingMap.get(userId);
            if (data == null) {
                data = new WasheUserPingData();
                data.setUserId(userId);
                pingMap.put(userId, data);
            }
            data.setPingTime(System.currentTimeMillis());
            data.setDisconnect(false);
        }
    }

    public static void checkPingByTimer() {

        if (washeConfig == null) {
            return;
        }

        // 超过该时间未ping就设置为掉线
        long disconnectTime = (long) (washeConfig.getPingInterval() * washeConfig.getDisconnectPingTimes());

        synchronized (pingMap) {
            for (Map.Entry<Long, WasheUserPingData> entry : pingMap.entrySet()) {
                long userId = entry.getKey();
                WasheUserPingData pingData = entry.getValue();

                // 掉线了
                if (!pingData.isDisconnect() &&
                        System.currentTimeMillis() - pingData.getPingTime() > disconnectTime) {
                    pingData.setDisconnect(true);

                    // 上传掉线状态
                    WasheProto.ChannelWasheStatusReqMsg.Builder builder = WasheProto.ChannelWasheStatusReqMsg.newBuilder();
                    builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(getUserKey(userId)));
                    builder.setType(1);
                    GamePlayerMgr.sendChannelPacket(ChannelProtocol.N_WASHE_STATUS, builder, userId);

                    // 日志
                    AutoLogMgr.add(new LogWasheDisconnect(userId, 1, new Date(pingData.getPingTime())));
                }

                // 很久没ping的移除掉
                if (System.currentTimeMillis() - pingData.getPingTime() > DateHelper.DAY_MILLIONS) {
                    removePing(userId);

                    // 日志
                    AutoLogMgr.add(new LogWasheDisconnect(userId, 3, new Date(pingData.getPingTime())));
                }
            }
        }
    }

    public static boolean isMultiCard(int goodsId) {
        return washeConfig != null && washeConfig.getMultiCardId() == goodsId;
    }

    public static boolean isWasheActivityChat(int activityId) {
        return washeConfig != null && washeConfig.getActivityInfo().getActivityId() == activityId;
    }

    public static void addTempHistoryValue(Map<Integer, Long> typeValueMap, eWasheHonorMomentType type, long addValue) {
        Long oldValue = typeValueMap.getOrDefault(type.getIntValue(), 0L);
        typeValueMap.put(type.getIntValue(), oldValue + addValue);
    }

    public static boolean inRechargeTokenTime() {
        if (washeConfig == null) {
            return false;
        }
        WasheSeasonConfig seasonConfig = washeConfig.getWasheSeasonConfig();
        if (seasonConfig == null || seasonConfig.getSeasonId() <= WasheConfig.SEASON_ID_TEST) {
            return false;
        }

        long now = System.currentTimeMillis();
        if (now < seasonConfig.getBeginShowTime() || now > seasonConfig.getEndTime()) {
            return false;
        }

        return true;
    }

    public static int canPlayGame() {
        // 配置
        if (washeConfig == null) {
            return GameErrorCode.E_WASHE_NO_SYSTEM;
        }

        // 开关：禁止匹配 && 客户端隐藏入口
        if (SystemSwitchMgr.getLockSystemIdList().contains(eSystemId.WasheActivity.getValue())) {
            return GameErrorCode.E_WASHE_WEIHU;
        }

        // 2022年11月16日 热更代码
        String paramStr1 = washeConfig.getParamStr1();
        if (!StringUtils.isNullOrEmpty(paramStr1)) {
            List<Long> list = StringUtils.stringToLongList(paramStr1, "\\|"); // 分钟
            long now = System.currentTimeMillis();
            long subTime = now - DateHelper.getZeroTimeStamp(now);
            if (subTime < list.get(0) * DateHelper.MINUTE_MILLIONS || subTime > list.get(1) * DateHelper.MINUTE_MILLIONS) {
                return GameErrorCode.E_WASHE_NO_IN_PLAY_TIME;
            }
        }

        // 按时间段屏蔽匹配
        long now = System.currentTimeMillis();
        long subTime = now - DateHelper.getZeroTimeStamp(now);
        for (List<Long> list : washeConfig.getStopMatchTimeList()) {
            if (list.get(0) <= subTime && subTime < list.get(1)) {
                return GameErrorCode.E_WASHE_NO_IN_PLAY_TIME;
            }
        }

        // 系统开关，关掉后不能再匹配了，客户端点击会提示系统维护中
        boolean shield = SystemSwitchMgr.getLockSystemIdList().contains(eSystemId.WasheActivityShield.getValue());
        if (shield) {
            return GameErrorCode.E_WASHE_WEIHU;
        }

        return 0;
    }

    public static void checkTodayScene() {
        if (washeConfig != null) {
            // 10分钟主动请求一次
            if (System.currentTimeMillis() > syncSceneTime + DateHelper.MINUTE_MILLIONS * 10) {
                WasheUserKey userKey = getUserKey(0);
                WasheProto.ChannelWasheGetDaySceneReqMsg.Builder builder = WasheProto.ChannelWasheGetDaySceneReqMsg.newBuilder();
                builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(userKey));
                GamePlayerMgr.sendChannelPacket(ChannelProtocol.N_WASHE_GET_DAY_SCENE, builder, 0);
            }
        }
    }

    public static void updateTodayScene(List<Integer> list) {
        syncSceneTime = System.currentTimeMillis();
        sceneList = list;

        // 同步在线玩家
        WasheConfig config = WasheMgr.washeConfig;
        if (config != null) {
            for (GamePlayer player : GamePlayerMgr.getAllOnlinePlayer()) {
                WasheModule module = player.getModule(WasheModule.class);
                WasheUserData userData = module.getWasheUserData();
                if (userData != null) {
                    module.syncUserData(config, userData, module.getWasheUserJinBiaoData());
                }
            }
        }
    }

    public static List<Integer> getSceneList() {
        return sceneList;
    }

    public static List<Integer> removeZeroSkillId(List<Integer> skillIdList) {
        List<Integer> list = new ArrayList<>();
        for (int skillId : skillIdList) {
            if (skillId > 0) {
                list.add(skillId);
            }
        }
        return list;
    }

    /**
     * @param skillIdList 检查下这个参数，不能是协议里的list直接拿过来，不然会报错
     */
    public static int checkChooseSkill(List<Integer> skillIdList) {
        if (washeConfig == null) {
            return GameErrorCode.E_WASHE_NO_IN_PLAY_TIME;
        }
        // 旧版本，自动填充2个技能
        if (!eWasheFunction.ChangeSkill.isOpen(washeConfig.getVersion())) {
            if (skillIdList.size() == 0) {
                skillIdList.add(eWasheSkillType.Skill_1001.getValue());
                skillIdList.add(eWasheSkillType.Skill_1002.getValue());
            }
        }
        // 技能数量不对，提示没技能
        if (skillIdList.size() != 2) {
            return GameErrorCode.E_WASHE_NO_CHOOSE_SKILL;
        }
        // 技能重复
        if (Objects.equals(skillIdList.get(0), skillIdList.get(1))) {
            return GameErrorCode.E_WASHE_SKILL_REPEATED;
        }
        // 存在 && 开启
        Map<Integer, WasheSkillConfig> skillConfigMap = washeConfig.getSkillConfigMap();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!skillConfig.isOpen()) {
                return GameErrorCode.E_WASHE_SKILL_NO_OPEN;
            }
        }
        return 0;
    }

    // =========================================

    public static void addLastResultData(long userId, WasheProto.WasheGameOverMsg msg, boolean handle) {
        byte[] bytes = msg.toByteArray();
        String msgData = Base64.getEncoder().encodeToString(bytes);

        WasheLastResultData data = getLastResultData(userId);

        // 修改数据
        synchronized (data) {
            data.setSeason(washeConfig.getSeasonId());
            data.setMsgData(msgData);
            data.setHandle(handle);
            data.setRead(false);
            data.setTime(System.currentTimeMillis());
        }
    }

    public static WasheLastResultData getLastResultData(long userId) {
        synchronized (lastResultMap) {
            WasheLastResultData data = lastResultMap.get(userId);
            if (data == null) {
                data = WasheBusiness.getWasheLastResultData(userId);
                if (data == null) {
                    data = new WasheLastResultData();
                    data.setUserId(userId);
                    data.setSeason(WasheConfig.SEASON_ID_NULL);
                    data.setMsgData("");
                    data.setHandle(true);
                    data.setRead(true);
                    data.setTime(0);
                    data.setInsertOption();
                }
                lastResultMap.put(userId, data);
            }
            return data;
        }
    }

    // =========================================

    public static WasheTmpBadgeResult getCacheWasheTmpBadgeResult(long userId) {

        // 玩家在线刷线下数据
        GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(userId);
        if (onlinePlayer != null) {
            WasheModule washeModule = onlinePlayer.getModule(WasheModule.class);
            WasheUserData userData = washeModule.getWasheUserData();
            WasheUserJinBiaoData jinBiaoData = washeModule.getWasheUserJinBiaoData();
            if (userData != null) {
                List<UserBadge> list = new ArrayList<>(onlinePlayer.getModule(BadgeModule.class).getUserBadgeMap().getOrDefault(eBadgeType.Washe.getValue(), new ArrayList<>()));
                refreshWasheTmpBadgeResult(userId, list, userData, jinBiaoData);
            }
        }

        long now = System.currentTimeMillis();
        WasheTmpBadgeResult result = badgeResultMap.get(userId);

        // 看有没有数据，没有或者很久没更新，就读库
        if (result == null || now - result.getCreateTime() > DateHelper.MINUTE_MILLIONS) {
            synchronized (badgeResultMap) {
                if (result == null || now - result.getCreateTime() > DateHelper.MINUTE_MILLIONS) {
                    WasheUserData userData = WasheBusiness.getWasheUserData(userId);
                    WasheUserJinBiaoData jinBiaoData = WasheBusiness.getWasheUserJinBiaoData(userId);
                    List<UserBadge> list = UserBadgeBussiness.getUserBadgeList(userId, eBadgeType.Washe.getValue());
                    result = refreshWasheTmpBadgeResult(userId, list, userData, jinBiaoData);
                }
            }
        }

        return result;
    }

    public static WasheTmpBadgeResult refreshWasheTmpBadgeResult(long userId, List<UserBadge> washeBadgeList, WasheUserData userData, WasheUserJinBiaoData jinBiaoData) {

        int seasonId = washeConfig.getSeasonId();

        Map<Integer, Long> seasonScoreMap = userData == null ? new HashMap<>() : userData.getSeasonScoreMap();
        long curScore = seasonId == WasheConfig.SEASON_ID_NULL ? 0L : seasonScoreMap.getOrDefault(seasonId, 0L);

        Map<Integer, Long> jinBiaoSeasonScoreMap = jinBiaoData == null ? new HashMap<>() : jinBiaoData.getSeasonScoreMap();
        Long jinBiaoCurScoreCanNull = seasonId == WasheConfig.SEASON_ID_NULL ? null : jinBiaoSeasonScoreMap.get(seasonId);

        // 拿各个赛季勋章
        List<WasheTmpBadge> tmpBadgeList = new ArrayList<>();
        for (UserBadge badge : washeBadgeList) {
            BadgeConfig badgeConfig = BadgeConfigMgr.getBadgeConfig(badge.getBadgeType(), badge.getBadgeId());
            List<Integer> paramList = badgeConfig.getSeasonParamList();
            int season = paramList.get(0);
            boolean isRank = paramList.get(1) == 1;
            WasheTmpBadge tmpBadge = new WasheTmpBadge(
                    badge.getBadgeId(),
                    season,
                    seasonScoreMap.getOrDefault(season, 0L),
                    isRank,
                    jinBiaoSeasonScoreMap.get(season)
            );
            tmpBadgeList.add(tmpBadge);
        }

        // 当前
        WasheTmpBadge cur = null;
        for (WasheTmpBadge tmpBadge : tmpBadgeList) {
            if (tmpBadge.getSeasonId() == seasonId) {
                if (cur == null) {
                    cur = tmpBadge;
                }
                if (tmpBadge.isRank()) {
                    cur = tmpBadge;
                    break;
                }
            }
        }
        if (cur == null) {
            cur = new WasheTmpBadge(0, seasonId, curScore, false, jinBiaoCurScoreCanNull);
        }

        // 最高
        int topSeason = WasheConfig.SEASON_ID_NULL;
        long topScore = 0;
        for (Map.Entry<Integer, Long> entry : seasonScoreMap.entrySet()) {
            int tmpSeason = entry.getKey();
            long tmpScore = entry.getValue();
            if (tmpSeason <= WasheConfig.SEASON_ID_TEST || tmpSeason == seasonId) { // 历史最高不要当前赛季
                continue;
            }
            if (tmpScore > topScore ||
                    tmpScore == topScore && tmpSeason > topSeason) { // 取最高分 || 分数相同取新赛季
                topSeason = tmpSeason;
                topScore = tmpScore;
            }
        }
        long topSeasonJinBiaoScore = jinBiaoSeasonScoreMap.getOrDefault(topSeason, 0L);

        WasheTmpBadge top = null;
        if (topSeason > WasheConfig.SEASON_ID_TEST) {
            for (WasheTmpBadge tmpBadge : tmpBadgeList) {
                if (tmpBadge.getSeasonId() == topSeason) {
                    if (top == null) {
                        top = tmpBadge;
                    }
                    if (tmpBadge.isRank()) {
                        top = tmpBadge;
                        break;
                    }
                }
            }
        }
        if (top == null) {
            top = new WasheTmpBadge(0, topSeason, topScore, false, topSeasonJinBiaoScore);
        }

        // 勋章排个序
        tmpBadgeList.sort(new Comparator<WasheTmpBadge>() {
            @Override
            public int compare(WasheTmpBadge o1, WasheTmpBadge o2) {
                if (o1.getSeasonId() != o2.getSeasonId()) {
                    return o2.getSeasonId() > o1.getSeasonId() ? 1 : -1;
                }
                if (o1.isRank() != o2.isRank()) {
                    return o1.isRank() ? -1 : 1;
                }
                return 0;
            }
        });

        // 勋章列表不显示当前赛季的
        for (int i = 0; i < tmpBadgeList.size(); i++) {
            WasheTmpBadge tmpBadge = tmpBadgeList.get(i);
            if (tmpBadge.getSeasonId() == seasonId) {
                tmpBadgeList.remove(i);
                i--;
            }
        }

        WasheTmpBadgeResult result = new WasheTmpBadgeResult();
        result.setCur(cur);
        result.setTop(top);
        result.setList(tmpBadgeList);

        badgeResultMap.put(userId, result);

        return result;
    }

    // =========================================

    public static void addHistoryRank(int seasonId, int rankType, ConcurrentHashMap<Long, Integer> map, XSeasonUserRank topRank) {
        synchronized (historyRankMap) {
            Map<Integer, WasheHistoryRank> rankMap = historyRankMap.get(seasonId);
            if (rankMap == null) {
                historyRankMap.put(seasonId, new ConcurrentHashMap<>());
            }
            WasheHistoryRank historyRank = historyRankMap.get(seasonId).get(rankType);
            if (historyRank == null) {
                historyRank = new WasheHistoryRank();
                historyRank.setSeasonId(seasonId);
                historyRank.setUserRankMap(map);
                historyRank.setTopRank(topRank);
                historyRank.setRankType(rankType);
                historyRank.setInsertOption();
                historyRankMap.get(seasonId).put(rankType, historyRank);
            } else {
                historyRank.setUserRankMap(map);
                historyRank.setTopRank(topRank);
                historyRank.setUpdateOption();
            }
        }
    }

    public static int getHistoryRank(int seasonId, int rankType, long userId) {
        Map<Integer, WasheHistoryRank> rankMap = historyRankMap.get(seasonId);
        if (rankMap == null) {
            return -1;
        }
        WasheHistoryRank historyRank = rankMap.get(rankType);
        if (historyRank == null) {
            return -1;
        }

        return historyRank.getUserRankMap().getOrDefault(userId, -1);
    }

    public static Map<Integer, Map<Integer, WasheHistoryRank>> getHistoryRankMap() {
        return historyRankMap;
    }

    public static void tryAutoSendReward(int seasonId, int rankType) {
        Map<Integer, WasheHistoryRank> rankMap = historyRankMap.get(seasonId);
        if (rankMap == null) {
            return;
        }
        WasheHistoryRank historyRank = rankMap.get(rankType);
        if (historyRank == null || historyRank.isAutoSendReward()) {
            return;
        }

        WasheConfig config = WasheMgr.getWasheConfig();
        if (config == null) {
            return;
        }

        WasheSeasonConfig seasonConfig = config.getSeasonConfigMap().get(historyRank.getSeasonId());
        if (seasonConfig == null) {
            return;
        }

        long now = System.currentTimeMillis();
        if (now - seasonConfig.getEndShowTime() < DateHelper.HOUR_MILLIONS) {
            return; // 结束一小时内不发
        }

        // 【拿榜单配置】
        Map<Integer, SeasonRewardConfig> configMap = WasheBusiness.getSeasonRewardConfigMap(ChannelConfig.CHANNEL_CENTER_DB_PARAM, washeConfig.getActivityInfo().getActivityId(), seasonId)
                .getOrDefault(seasonId, new HashMap<>())
                .getOrDefault(eSeasonRewardType.WasheScoreRank.getIntValue(), new HashMap<>());

        // 【玩家一个个发】
        for (Map.Entry<Long, Integer> entry : historyRank.getUserRankMap().entrySet()) {
            long userId = entry.getKey();
            int rank = entry.getValue();

            Map<Integer, SeasonRewardData> dataMap;
            GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(userId);
            if (onlinePlayer != null) {
                dataMap = onlinePlayer.getModule(SeasonRewardModule.class)
                        .getSeasonRewardDataMap(eSystemId.WasheActivity.getValue(), seasonId, eSeasonRewardType.WasheScoreRank);
            } else {
                dataMap = SeasonRewardBusiness.getSeasonRewardDataMap(userId, eSystemId.WasheActivity.getValue(), seasonId)
                        .getOrDefault(eSeasonRewardType.WasheScoreRank.getIntValue(), new HashMap<>());
            }
            if (dataMap.size() != 1) {
                getLogger().error("washe auto send big rank reward error, userId {}, seasonId {}, rank {}, season reward data num error!", userId, seasonConfig, rank);
                continue;
            }

            SeasonRewardData data = new ArrayList<>(dataMap.values()).get(0);
            if (data.isGetReward()) {
                continue;
            }

            // 拿奖励配置
            SeasonRewardConfig rewardConfig = SeasonHelper.getRankRewardConfigByMyRank(configMap, rank);
            if (rewardConfig == null) {
                continue;
            }

            // 修改发奖状态
            data.setGetReward(true);
            if (!SeasonRewardBusiness.updateSeasonRewardData(data)) {
                getLogger().error("washe auto send big rank reward save db fail, userId {}, seasonId {}, rank {}.", userId, seasonConfig, rank);
                continue;
            }

            getLogger().debug("washe auto send big rank reward, userId {}, seasonId {}, rank {}.", userId, seasonId, rank);

            // 发奖
            UserInfo userInfo = UserMgr.getUserInfo(userId);
            String language = userInfo.getLanguage();
            String activityName = ActivityMgr.getActivityName(config.getActivityInfo(), language);
            String mailTitle = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.AUTO_SEND_ACTIVITY_CROSS_RANK_REWARD_TITLE, language), activityName);
            String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.AUTO_SEND_ACTIVITY_CROSS_RANK_REWARD_CONTENT, language), activityName);
            MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), rewardConfig.getReward(), mailContent, mailTitle);
        }

        // 修改发奖状态
        historyRank.setAutoSendReward(true);
        historyRank.setUpdateOption();
    }

    public static void tryAutoSendZhanLingReward() {
        if (washeConfig == null) {
            return;
        }

        // 【找刚过期的赛季配置】
        WasheSeasonConfig curConfig = null;
        long now = System.currentTimeMillis();
        for (WasheSeasonConfig seasonConfig : washeConfig.getSeasonConfigMap().values()) {
            if (!autoZhanLingSeasonSet.contains(seasonConfig.getSeasonId()) && now > seasonConfig.getEndShowTime() + DateHelper.HOUR_MILLIONS
                    && now < seasonConfig.getEndShowTime() + DateHelper.DAY_MILLIONS * 12) {
                curConfig = seasonConfig;
                break;
            }
        }
        if (curConfig == null || curConfig.getSeasonId() <= WasheConfig.SEASON_ID_TEST || autoZhanLingSeasonSet.contains(curConfig.getSeasonId())) {
            return;
        }
        getLogger().debug("washe auto send zhanLing reward begin... activityId {}, seasonId {}.", curConfig.getActivityId(), curConfig.getSeasonId());

        // 【读库拿配置和要发奖的玩家】
        Map<Integer, SeasonRewardConfig> configMap = WasheBusiness.getWasheZhanLingConfigMap(ChannelConfig.CHANNEL_CENTER_DB_PARAM, curConfig.getActivityId(), curConfig.getSeasonId());
        Map<Long, WasheUserData> userDataMap = WasheBusiness.getWasheUserDataMapByDataSeason(curConfig.getSeasonId()); // 按赛季过滤下减少数据量

        // 【先修改总的发奖状态比较稳】
        autoZhanLingSeasonSet.add(curConfig.getSeasonId());

        // 【按玩家发奖】
        for (Map.Entry<Long, WasheUserData> entry : userDataMap.entrySet()) {
            long userId = entry.getKey();
            WasheUserData userData = entry.getValue();

            // 拿一下购买的战令（0无，1白银，2黄金）
            Set<Long> buySet = new HashSet<>();
            buySet.add(0L);
            if (userData.getSilverSet().contains(curConfig.getSeasonId())) {
                buySet.add(1L);
            }
            if (userData.getGoldSet().contains(curConfig.getSeasonId())) {
                buySet.add(2L);
            }

            // 读库拿奖励数据
            Map<Integer, SeasonRewardData> rewardDataMap = SeasonRewardBusiness.getWasheNoGetRewardZhanLingMap(userId, curConfig.getSeasonId());

            // 遍历奖励
            Property totalReward = new Property();
            for (SeasonRewardData rewardData : rewardDataMap.values()) {

                SeasonRewardConfig rewardConfig = configMap.get(rewardData.getRewardId());
                if (rewardConfig == null) {
                    getLogger().error("washe auto send zhanLing reward no config error! userId {}, activityId {}, seasonId {}, rewardId {}.",
                            userId, curConfig.getActivityId(), curConfig.getSeasonId(), rewardData.getRewardId());
                    continue;
                }

                if (!rewardData.isGetReward()) { // 未领奖
                    if (rewardData.getValue() >= rewardConfig.getParamList().get(0)) { // 达到值
                        if (buySet.contains(rewardConfig.getParamList().get(1))) { // 有买战令

                            // 修改领奖状态
                            rewardData.setGetReward(true);
                            rewardData.setTime(System.currentTimeMillis());
                            if (!SeasonRewardBusiness.updateSeasonRewardData(rewardData)) {
                                getLogger().error("washe auto send zhanLing reward update data error! userId {}, activityId {}, seasonId {}, rewardId {}.",
                                        userId, curConfig.getActivityId(), curConfig.getSeasonId(), rewardData.getRewardId());
                                continue;
                            }

                            // 添加奖励
                            totalReward.addProperty(PropertyHelper.parseStringToProperty(rewardConfig.getReward()));
                        }
                    }
                }

            }

            if (totalReward.isNothing()) {
                continue;
            }

            // 发奖
            String totalRewardStr = PropertyHelper.parsePropertyToString(totalReward);
            getLogger().debug("washe auto send zhanLing reward mail log... userId {}, activityId {}, seasonId {}, reward : {}.",
                    userId, curConfig.getActivityId(), curConfig.getSeasonId(), totalRewardStr);
            UserInfo userInfo = UserMgr.getUserInfo(userId);
            String language = userInfo.getLanguage();
            String activityName = ActivityMgr.getActivityName(washeConfig.getActivityInfo(), language);
            String mailTitle = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.AUTO_SEND_ACTIVITY_CONDITION_REWARD_TITLE, language), activityName);
            String mailContent = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.AUTO_SEND_ACTIVITY_CONDITION_REWARD_CONTENT, language), activityName);
            MailManager.sendMail(userId, eMailType.SYSTEM.getValue(), totalRewardStr, mailContent, mailTitle);

        }

        getLogger().debug("washe auto send zhanLing reward finish... activityId {}, seasonId {}.", curConfig.getActivityId(), curConfig.getSeasonId());
    }

    // =========================================

    @Override
    public boolean save() {

        for (WasheLastResultData data : lastResultMap.values()) {
            if (data.isInsertOption()) {
                WasheBusiness.addWasheLastResultData(data);
            } else if (data.isUpdateOption()) {
                WasheBusiness.updateWasheLastResultData(data);
            }
        }

        for (Map<Integer, WasheHistoryRank> rankMap : historyRankMap.values()) {
            for (WasheHistoryRank historyRank : rankMap.values()) {
                if (historyRank.isInsertOption()) {
                    WasheBusiness.addWasheHistoryRank(historyRank);
                } else if (historyRank.isUpdateOption()) {
                    WasheBusiness.updateWasheHistoryRank(historyRank);
                }
            }
        }


        // 半夜四点移除旧数据
        if (DateHelper.getHours() == 4) {

            for (WasheLastResultData data : lastResultMap.values()) {
                if (GamePlayerMgr.getOnlinePlayer(data.getUserId()) == null && data.getOp() == DataStatus.None) {
                    lastResultMap.remove(data.getUserId());
                }
            }

            if (System.currentTimeMillis() - badgeClearTime > DateHelper.HOUR_MILLIONS) {
                synchronized (badgeResultMap) {
                    badgeClearTime = System.currentTimeMillis();
                    badgeResultMap.clear();
                }
            }

        }

        return true;
    }

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        historyRankMap = WasheBusiness.getWasheHistoryRankMap();
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

}
